package com.example.server.plugins.routing

import com.example.server.plugins.AuthorizationException
import io.ktor.resources.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.auth.jwt.*
import io.ktor.server.resources.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.util.pipeline.*
import kotlinx.serialization.Serializable
import org.slf4j.Logger
import org.slf4j.LoggerFactory


private val logger: Logger = LoggerFactory.getLogger("authenticate")


internal object PermHook : Hook<suspend (ApplicationCall) -> Unit> {
    internal val AuthenticatePhase: PipelinePhase = PipelinePhase("Perm")

    override fun install(
        pipeline: ApplicationCallPipeline,
        handler: suspend (ApplicationCall) -> Unit
    ) {
        pipeline.insertPhaseAfter(ApplicationCallPipeline.Plugins, AuthenticatePhase)
        pipeline.intercept(AuthenticatePhase) { handler(call) }
    }
}

fun Route.perm(
    build: Route.() -> Unit
) {
    val r = createChild(object : RouteSelector() {
        override fun evaluate(context: RoutingResolveContext, segmentIndex: Int): RouteSelectorEvaluation {
            return RouteSelectorEvaluation.Transparent
        }
    })
    r.install(createRouteScopedPlugin("perm") {
        on(PermHook) {
            val p = it.principal<JWTPrincipal>()
            if (p == null) {
                logger.info("======用户未登录===========")
                throw AuthorizationException("未登录")
            } else {
                val u = p["username"]
                // 这里可以做统一鉴权判断
                if (u != "admin") {
                    logger.info("用户 [$u] 没有权限")
                    throw AuthorizationException("没有权限")
                } else {
                    logger.info("用户 [$u] 有权限干这事")
                }
            }
        }
    })
    r.build()
}

/**
 * 类型测试
 */
fun Route.configTypeRouting() {
    authenticate("auth-jwt") {
        // authentication  鉴权
        //
        perm {
            get("/hello") {
                logger.info("==鉴权成功，进来了==========")
                val p = call.principal<JWTPrincipal>()
                call.respondText("Hello World! ${p?.get("username")}")
            }
        }

        get<MyLocation> {
            call.respondText("Location: name=${it.name}, arg1=${it.arg1}, arg2=${it.arg2}")
        }
    }
    // Register nested routes
    get<Type.Edit> {
        call.respondText("Inside $it")
    }
    get<Type.List> {
        call.respondText("Inside $it")
    }
}


@Serializable
@Resource("/location/{name}")
class MyLocation(val name: String, val arg1: Int = 42, val arg2: String = "default")

@Serializable
@Resource("/type/{name}")
data class Type(val name: String) {
    @Serializable
    @Resource("/edit")
    data class Edit(val type: Type)

    @Serializable
    @Resource("/list/{page}")
    data class List(val type: Type, val page: Int)
}
